﻿using System;
using System.Activities;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Threading;
using Reactor.Extensions;
using Reactor.Workflow.Activities;

namespace Reactor.ServiceGrid.Workflows.Activities
{
    public class InstallAsWindowsService : ReactorCodeActivityBase
    {
        [RequiredArgument]
        public InArgument<ServiceIdentifier> ServiceIdentifier { get; set; }

        [RequiredArgument]
        public InArgument<string> ServiceExecutablePath { get; set; }

        #region Overrides of CodeActivity

        /// <summary>
        /// When implemented in a derived class, performs the execution of the activity.
        /// </summary>
        /// <param name="context">The execution context under which the activity executes.</param>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")]
        protected override void Execute(CodeActivityContext context)
        {
            var serviceIdentifier = context.GetValue(ServiceIdentifier);
            var serviceName = serviceIdentifier.ToServiceInstanceString();
            var executablePath = context.GetValue(ServiceExecutablePath);

            // First see if there is already a service by this name installed.
            // If so, try to stop the service.
            var serviceController = ServiceController.GetServices().SingleOrDefault(s => s.ServiceName == serviceName);
            if(serviceController != null)
            {
                if (Log.IsDebugEnabled) Log.DebugFormat("ServiceController for service: {0} already present. No need to install from command line.", serviceName);

                serviceController.Refresh();
                string failureReason;
                if (!serviceController.TryStop(TimeSpan.FromSeconds(30), out failureReason))
                    throw new ApplicationException(failureReason);
            }
            else
            {
                // Install as windows service
                Log.DebugFormat("Attempting to install service using the following command: {0} install", executablePath);
                Process.Start(executablePath, " -i");
                Thread.Sleep(2000);    // Wait for Windows to create the service
                Log.Debug("Finished waiting for service to install. Will now check to see if it is registered as a Windows Service.");

                // Verify service was installed
                serviceController = ServiceController.GetServices().SingleOrDefault(s => s.ServiceName == serviceName);
                if (serviceController == null)
                    throw new ApplicationException(string.Format("Windows Service named {0} not found after attempting to install it.", serviceName));
            }
        }

        #endregion
    }
}
